
#include <string>
#include <vector>
#include <algorithm>
#include <dnet.h>


namespace huluwa {
namespace net {
namespace impl {

class InterfaceImpl {

public:
    /// Get interface name.
    std::string GetName() const 
    {
        return intf_.intf_name;
    }

    /// Detemine whether interface type is ethernet.
    bool IsEthernet() const
    {
        return intf_.intf_type == INTF_TYPE_ETH;
    }

    /// Detemine whether interface type is loopback.
    bool IsLoopback() const
    {
        return intf_.intf_type == INTF_TYPE_LOOPBACK;
    }

    /// Detemine whether interface up flag is set.
    bool IsUpFlag() const
    {
        return intf_.intf_flags & INTF_FLAG_UP;
    }

    /// Detemine whether interface loopback flag is set.
    bool IsLoopbackFlag() const
    {
        return intf_.intf_flags & INTF_FLAG_LOOPBACK;
    }

    /// Detemine whether interface broadcast flag is set.
    bool IsBroadcastFlag() const 
    {
        return intf_.intf_flags & INTF_FLAG_BROADCAST;
    }

    /// Detemine whether interface multicast flag is set.
    bool IsMulticastFlag() const
    {
        return intf_.intf_flags & INTF_FLAG_MULTICAST;
    }

    /// Detemine whether interface disabled ARP.
    bool IsDisableARP() const
    {
        return intf_.intf_flags & INTF_FLAG_NOARP;
    }

    /// Get interface MTU.
    std::size_t GetMTU() const 
    {
        return static_cast<std::size_t>(intf_.intf_mtu);
    }

    template<class Fun>
    static void DumpInterface(Fun& fun)
    {
        intf_t *intf = intf_open();
        std::vector<InterfaceImpl *> pool;

        intf_loop(intf, LoopCallback, &pool);
        std::for_each(pool.begin(), pool.end(), fun);

        intf_close(intf);
    }

private:
    /// Construct from dnet intf_entry structure.
    InterfaceImpl(const struct intf_entry *intf)
        : intf_(*intf)
    {}

    static int LoopCallback(const struct intf_entry* entry, void *arg)
    {
        typedef std::vector<InterfaceImpl *> ContainerType;

        ContainerType *pool = reinterpret_cast<ContainerType *>(arg);

        pool->push_back(new InterfaceImpl(entry));

        return 0;
    }

    struct intf_entry intf_;
};

} // namespace impl
} // namespace net
} // namespace huluwa
